/*************************************************************************
	> File Name: MemExcursionLimiter.c
	> Author: 
	> Mail: 
	> Created Time: 2018/1/22 mon 15:12
	> Version     :
 ************************************************************************/

#include<stdio.h>

#include "BaseAlgo.h"
#include "MemExcursionLimiter.h"
#include "AwinicLog.h"

static void memDataMulpyGain(int32_t *data,int32_t gain,uint16_t dataCnt)
{
    uint16_t i;

    for(i=0;i<dataCnt;i++)
    {
        data[i] = int32Mulint32(data[i],gain,MembraneFilterGainBit);
    }
}
/***********************************************************************************************
 * *Name        :memDecimateProcess
 * *Description :Data Decimate Process
 * *Parameter   :inData ,decimate configuration
 * *Return Value: effective data number after decimate
 * *Version: v1.0.0
 * ********************************************************************************************/
static uint16_t memDecimateProcess(int32_t *data,decCfg_t *cfg,uint16_t wordsCnt,uint16_t enable)
{
    uint16_t i;
    uint16_t decCnt;

    if(DEC_ENABLE != (DEC_ENABLE_MASK&enable))
        return wordsCnt;

    //AWLOGD("dec gain %d \n",cfg->gain);
    memDataMulpyGain(data,cfg->gain,wordsCnt);
    //write_pcm("../data/memDecGain.pcm",data,wordsCnt);
    for(i=0;i<DEC_FILTER_NUM;i++)
    {
        filterProcess(data,&cfg->ft_cfg[i],wordsCnt);
    }
    //write_pcm("../data/memDecfilter.pcm",data,wordsCnt);

    decCnt = wordsCnt/DEC_TIMES_NUM;
    if(wordsCnt%DEC_TIMES_NUM !=0)
        decCnt++;

    for(i=0;i<decCnt;i++)
    {
        data[i] = data[i*DEC_TIMES_NUM];
    }

    return decCnt;
}
static void memDecimateInit(decCfg_t *cfg)
{
     int i;

     for(i=0;i<DEC_FILTER_NUM;i++)
     {
         filterInit(&cfg->ft_cfg[i]);
     }
}
static void memDecimateReset(decCfg_t *cfg)
{
     int i;

     for(i=0;i<DEC_FILTER_NUM;i++)
     {
         filterReset(&cfg->ft_cfg[i]);
     }
    
}
static int memDecimateSetParam(decCfg_t *cfg,decParams_t *params)
{
    int i;

    if(params->gain == 0)
    {
    	AWLOGE(" Gain is Zero\n");
    	return -1;
    }
    cfg->gain = params->gain;
    for(i=0;i<DEC_FILTER_NUM;i++)
    {
        filterSetParams(&cfg->ft_cfg[i],&params->ft_params[i]);
    }
    return 0;
}
static void memDecimateGetParam(decCfg_t *cfg,decParams_t *params)
{
    int i;
    params->gain = cfg->gain;

    for(i=0;i<DEC_FILTER_NUM;i++)
    {
        filterGetParams(&cfg->ft_cfg[i],&params->ft_params[i]);
    }
}
static void memUndecimateProcess(int32_t *data,uint16_t inDataCnt,uint16_t outDataCnt)
{
    uint16_t i,j;
    uint16_t count;
    int32_t *outData,*inData;

    if(inDataCnt == outDataCnt)
        return;

    inData = data + (outDataCnt - inDataCnt);

    //move orgin data to buffer tail
    for(i=0;i<inDataCnt;i++)
    {
        inData[i] = data[i];
    }

    outData = data;

    if(outDataCnt%inDataCnt ==0)
    {
        for(i=0;i<inDataCnt;i++)
        {
            for(j=0;j<DEC_TIMES_NUM;j++)
            {
                outData[i*DEC_TIMES_NUM+j] = inData[i];
            }
        }
    }else{
        count = outDataCnt/DEC_TIMES_NUM;
        for(i=0;i<count;i++)
        {
            for(j=0;j<DEC_TIMES_NUM;j++)
            {
                outData[i*DEC_TIMES_NUM+j] = inData[i];
            }
        }
        j = outDataCnt - count*DEC_TIMES_NUM;
        for(i=0;i<j;i++)
        {
            outData[count*DEC_TIMES_NUM+i]= inData[count];
        }
    }
}
/***********************************************************************************************
 * *Name        :memExcursionFilterProcess
 * *Description :Excursion Filter process
 * *Parameter   :Data ,Excursion Configuration ,Input Data Number
 * *Return Value: NULL
 * *Version: v1.0.0
 * ********************************************************************************************/
static void memExcursionFilterProcess(int32_t *data,exCfg_t *cfg,uint16_t wordsCnt)
{
    uint16_t i;
    memDataMulpyGain(data,cfg->gain,wordsCnt);
    //AWLOGD("ex Gain %d\n",cfg->gain);
    //write_pcm("../data/memExGain.pcm",data,wordsCnt);
    for(i=0;i<EX_FILTER_NUM;i++)
    {
        filterProcess(data,&cfg->ft_cfg[i],wordsCnt);
    }
}
static void memExcursionfilterInit(exCfg_t *cfg)
{
    int i;
    for(i=0;i<EX_FILTER_NUM;i++)
    {
        filterInit(&cfg->ft_cfg[i]);
    }
}
static void memExcursionfilterReset(exCfg_t *cfg)
{
    int i;
    for(i=0;i<EX_FILTER_NUM;i++)
    {
        filterReset(&cfg->ft_cfg[i]);
    }
}
static int memExcursionfilterSetParams(exCfg_t *cfg,exParams_t *params)
{
    int i;
    if(params->gain == 0)
    {
    	AWLOGE("Gain Is Zero\n");
    	return -1;
    }
    cfg->gain = params->gain;
    for(i=0;i<EX_FILTER_NUM;i++)
    {
        filterSetParams(&cfg->ft_cfg[i],&params->ft_params[i]);
    }
    return 0;
}
static void memExcursionfilterGetParams(exCfg_t *cfg,exParams_t *params)
{
    int i;

    params->gain = cfg->gain ;
    for(i=0;i<EX_FILTER_NUM;i++)
    {
        filterGetParams(&cfg->ft_cfg[i],&params->ft_params[i]);
    }
}
/***********************************************************************************************
 * *Name        :memExLimiterProcess
 * *Description :membrane Excursion  process
 * *Parameter   :Data ,membrane Excursion Configuration ,Input Data Number
 * *Return Value: NULL
 * *Version: v1.0.0
 * ********************************************************************************************/
void memExLimiterProcess(int32_t *data,memExLimiterCfg_t *cfg,uint16_t dataCnt)
{
    int dataDecCnt; //store return value after decimate
    
    //Decimate Process
    dataDecCnt = memDecimateProcess(data,&cfg->dec_cfg,dataCnt,cfg->moduleEnable);
    //write_pcm("../data/memDecimate.pcm",data,dataDecCnt);
    //Excursion filter process
    memExcursionFilterProcess(data,&cfg->ex_cfg,dataDecCnt);
    //write_pcm("../data/memEx.pcm",data,dataDecCnt);
    //peak detector process
    peakDetectorProcess(data,&cfg->pd_cfg,dataDecCnt);
    //write_pcm("../data/peakDet.pcm",data,dataDecCnt);
    //data curve process 
    curveProcess(data,&cfg->gcur_cfg,dataDecCnt);
    //write_pcm("../data/curve.pcm",data,dataDecCnt);
    //data smooth process
    smoothProcess(data,&cfg->gs_cfg,dataDecCnt);
    //write_pcm("../data/smooth.pcm",data,dataDecCnt);
    //data undecimate to origin count
    memUndecimateProcess(data,dataDecCnt,dataCnt);
    //write_pcm("../data/memUndec.pcm",data,dataCnt);

}
int  memExLimiterInit(memExLimiterCfg_t *cfg)
{
    memDecimateInit(&cfg->dec_cfg);
    memExcursionfilterInit(&cfg->ex_cfg);
    peakDetectorInit(&cfg->pd_cfg);
    curveInit(&cfg->gcur_cfg);
    smoothInit(&cfg->gs_cfg);
    return 0;
}
int  memExLimiterReset(memExLimiterCfg_t *cfg)
{
    memDecimateReset(&cfg->dec_cfg);
    memExcursionfilterReset(&cfg->ex_cfg);
    peakDetectorReset(&cfg->pd_cfg);
    curveReset(&cfg->gcur_cfg);
    smoothReset(&cfg->gs_cfg);
    return 0;
}
int memExLimiterSetParams(memExLimiterCfg_t *cfg,memExLimiterParams_t *params,int32_t threshold)
{
	int ret = 0;
    cfg->moduleEnable = params->moduleEnable;
    ret = memDecimateSetParam(&cfg->dec_cfg,&params->dec_params);
    if(ret <0)
    {
    	//AWLOGE(" memDecimateSetParam is Zero\n");
    	return -1;
    }
    ret = memExcursionfilterSetParams(&cfg->ex_cfg,&params->ex_params);
    if(ret <0)
    {
    	//AWLOGE(" memExcursionfilterSetParams is Zero\n");
    	return -1;
    }
    peakDetSetParams(&cfg->pd_cfg,&params->pd_params);
    curveSetParams(&cfg->gcur_cfg,&params->gcur_params,threshold);
    smoothSetParams(&cfg->gs_cfg,&params->gs_params);
    return 0;
}
int memExLimiterGetParams(memExLimiterCfg_t *cfg,memExLimiterParams_t *params,int32_t *threshold)
{
    params->moduleEnable = cfg->moduleEnable;
    memDecimateGetParam(&cfg->dec_cfg,&params->dec_params);
    memExcursionfilterGetParams(&cfg->ex_cfg,&params->ex_params);
    peakDetGetParams(&cfg->pd_cfg,&params->pd_params);
    curveGetParams(&cfg->gcur_cfg,&params->gcur_params,threshold);
    smoothGetParams(&cfg->gs_cfg,&params->gs_params);
    return 0;
}
